package chapter_12
import scala.collection.mutable.ArrayBuffer


abstract class IntQueue {
  def get(): Int
  def put(x: Int)
}


class BasicIntQueue extends IntQueue{
  // 基本的“纯净”队列
  private val buf = new ArrayBuffer[Int]
  def get() = buf.remove(0) // “实现”接口的时候override是可选的
  def put(x: Int) { buf += x}
}


trait Doubling extends IntQueue {
  /*
  Doubling特质的超类是IntQueue。这个定义意味着特质只能混入扩展了IntQueue的类中。
  因此你可以把Doubling混入到BasicIntQueue，但是不能混入Rational。
  特质在声明为抽象的方法中有一个super调用。这种调用对于普通的类来说是非法，因为它们在
  执行时将必然失败。然而对于特质来说，这样的调用实际能够成功。因为特质里的super调用是
  动态绑定的，特质Doubling的super调用将直到被混入另一个特质或类之后，有了具体的方法定
  义时才工作。
  这种安排对于实现可堆叠改动的特质来说是常常要用到的。为了告诉编译器你的目的，你必须对这
  种方法打上abstract override的标志。这种标识符的组合仅在特质成员的定义中被认可，在类中
  则不行，它意味着特质必须被混入到某个具有期待方法的具体定义的类中。
   */
  abstract override def put(x: Int) { super.put(2 * x) }
}


trait Incrementing extends IntQueue {
  abstract override def put(x: Int) = { super.put(x + 1) }
}


trait Filtering extends IntQueue {
  abstract override def put(x: Int) = {
    if (x >=0) super.put(x)
  }
}


class MyQueue extends BasicIntQueue with Doubling {}


object TraitQueue {
  def main(args: Array[String]): Unit = {
//    val queue = new BasicIntQueue
//    val queue = new MyQueue
    val queue = new BasicIntQueue with Doubling
    queue.put(10)
    queue.put(20)
    println(queue.get())
    println(queue.get())

    // 多个特质混入
    val queue2 = new BasicIntQueue with Incrementing with Filtering
//    val queue2 = new BasicIntQueue with Filtering with Incrementing
    /*
    多个特质的混入顺序是十分重要的。粗略地说，越靠近右边的特质越先起作用。当你调用带混入
    的类的方法时，最右侧特质的方法首先被调用。如果那个方法调用了super，它调用其左侧特质
    的方法，依此类推。上面的例子里，Filtering的put首先被调用，因此它移除了开始的负数。
    Incrementing的put第二个被调用，因此它对剩下的整数增量。如果逆转顺序，那么整数首先
    会加1，然后如果仍然是负的才会被抛弃。
     */
    queue2.put(-1)
    queue2.put(10)
    queue2.put(20)
    println(queue2.get())
    println(queue2.get())
  }
}
